#include "U2SearchOps.h"
#include <stdio.h>
#include <ctype.h>

/* Win32 directory operations emulation */
#if U2_PLATFORM != U2_PLATFORM_WIN32


struct _find_search_t
{
	char *pattern;
	char *curfn;
	char *directory;
	int dirlen;
	DIR *dirfd;
};

long _findfirst(const char *pattern, struct _finddata_t *data)
{
	_find_search_t *fs = new _find_search_t;
	fs->curfn = NULL;
	fs->pattern = NULL;

	// Separate the mask from directory name
	const char *mask = strrchr (pattern, '/');
	if (mask)
	{
		fs->dirlen = mask - pattern;
		mask++;
		fs->directory = (char *)malloc (fs->dirlen + 1);
		memcpy (fs->directory, pattern, fs->dirlen);
		fs->directory [fs->dirlen] = 0;
	}
	else
	{
		mask = pattern;
		fs->directory = strdup (".");
		fs->dirlen = 1;
	}

	fs->dirfd = opendir (fs->directory);
	if (!fs->dirfd)
	{
		_findclose ((long)fs);
		return -1;
	}

	/* Hack for "*.*" -> "*' from DOS/Windows */
	if (strcmp (mask, "*.*") == 0)
		mask += 2;
	fs->pattern = strdup (mask);

	/* Get the first entry */
	if (_findnext ((long)fs, data) < 0)
	{
		_findclose ((long)fs);
		return -1;
	}

	return (long)fs;
}

int _findnext(long id, struct _finddata_t *data)
{
	_find_search_t *fs = (_find_search_t *)id;

	/* Loop until we run out of entries or find the next one */
	dirent *entry;
	for (;;)
	{
		if (!(entry = readdir (fs->dirfd)))
			return -1;

		/* See if the filename matches our pattern */
		if (fnmatch (fs->pattern, entry->d_name, 0) == 0)
			break;
	}

	if (fs->curfn)
		free (fs->curfn);
	data->name = fs->curfn = strdup (entry->d_name);

	size_t namelen = strlen (entry->d_name);
	char *xfn = new char [fs->dirlen + 1 + namelen + 1];
	sprintf (xfn, "%s/%s", fs->directory, entry->d_name);

	/* stat the file to get if it's a subdir and to find its length */
	struct stat stat_buf;
	if (stat (xfn, &stat_buf))
	{
		// Hmm strange, imitate a zero-length file then
		data->attrib = _A_NORMAL;
		data->size = 0;
	}
	else
	{
		if (S_ISDIR(stat_buf.st_mode))
			data->attrib = _A_SUBDIR;
		else
			/* Default type to a normal file */
			data->attrib = _A_NORMAL;

		data->size = stat_buf.st_size;
	}

	delete [] xfn;

	/* Files starting with a dot are hidden files in Unix */
	if (data->name [0] == '.')
		data->attrib |= _A_HIDDEN;

	return 0;
}

int _findclose(long id)
{
	int ret;
	_find_search_t *fs = (_find_search_t *)id;

	ret = fs->dirfd ? closedir (fs->dirfd) : 0;
	free (fs->pattern);
	free (fs->directory);
	if (fs->curfn)
		free (fs->curfn);
	delete fs;

	return ret;
}

#endif